use std::borrow::Cow;
use serde::Serialize;
use thiserror::Error;
use std::error::Error as StdErr;

pub type IoErr = std::io::Error;
pub type SqlxErr = sqlx::Error; 

pub type CustomErr = Cow<'static, str>;

#[derive(Debug, Error)]
pub enum AppErr {

    #[error("io:{0}")]
    Io(#[from] IoErr),

    #[error("sqlx:{0}")]
    Sqlx(#[from] SqlxErr),  

    #[error("{0}")]
    Custom(CustomErr),
}

impl Serialize for AppErr {

    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: serde::Serializer {
        serializer.serialize_str(&self.to_string())
    }
}

pub fn static_msg(msg: &'static str) -> AppErr {
    AppErr::Custom( Cow::Borrowed(msg) )
}

pub fn static_err<V>(msg: &'static str) -> Result<V, AppErr> {
    Err( AppErr::Custom( Cow::Borrowed(msg) ) )
}


pub trait ErrorHandler<T> {
    
    fn map_app(self, msg: &str) -> Result<T, AppErr>;
}

impl <E: StdErr, T> ErrorHandler<T> for Result<T, E> {

    #[inline]
    fn map_app(self, msg: &str) -> Result<T, AppErr> {
        match self {
            Ok(v) => return Ok(v),
            Err(e) => {
                let s = format!("{}=>{}", msg, e.to_string());
                return Err( AppErr::Custom(Cow::Owned(s)) );
            }
        };
    }   
}


